const fs = require('fs');
const nedb = require('nedb');

class Genshin{
    constructor(dbMember){
        this.userIDs = [];
        this.dbMember = dbMember;
        this.primoGems = {};// primoGems[userID]
        this.last4star = {};// last4star[userID], 0-9   距离上一次抽出4星的抽数,用于判断保底
        this.last5star = {};// last5star[userID], 0-89  距离上一次抽出5星的抽数,用于判断保底
        this.dbUserDatas = {Inventory:{}, History:{}};
        this.Pool = JSON.parse(fs.readFileSync('./res/JSON/CardPool.json'));
    };

    // 初始化部分
    async Init(userIDs){
        await this.memberInit(userIDs);
        await new Promise((resolve) => setTimeout(resolve, 20));
        await this.starInit(userIDs);// 最抽象的一集 
    };// 先后调用memberInit, starInit进行初始化
    async memberInit(userIDs){
        this.userIDs = userIDs;
        console.log("================UserDatasInit================");
        for (let userID of userIDs){
            for(let dbtype of ["Inventory", "History"]){
                fs.stat(`./res/DataBase/GenshinUser${dbtype}/User${userID}.db`,
                (err,stats) => {
                    if(err || stats.isFile()) {
                        this.dbUserDatas[dbtype][userID]
                            = new nedb({filename: `./res/DataBase/GenshinUser${dbtype}/User${userID}.db`,
                                        autoload: true});
                        console.log(`User${userID}.db \t${dbtype}初始化`);
                    }else console.log(`User${userID}.db \t${dbtype}错误`);
                });
            };
            this.dbMemberFind(userID, "primoGem")
                    .then((primoGem)=> {
                        this.primoGems[userID] = primoGem ?? 0;
                        console.log(`User${userID}  \t${this.primoGems[userID]}原石`);
                    });
        };
    };
    async starInit(userIDs){
        try{
            for(let userID of userIDs){
                let history = await this.getUserHistory(userID);
                for(let i = history.length - 1; i >= 0; i--){
                    if(this.last5star[userID] !== undefined && this.last4star[userID] !== undefined)
                        break;
                    else if(history[i].star === 5 && this.last5star[userID] === undefined)
                        this.last4star[userID] = history.length - 1 - i;
                    else if(history[i].star === 4 && this.last4star[userID] === undefined)
                        this.last5star[userID] = history.length - 1 - i;
                };
                this.last5star[userID] = this.last5star[userID] ?? 0;
                this.last4star[userID] = this.last4star[userID] ?? 0;
            };
        }catch(err){console.log("[ERROR]  GenshinUserStarInitERR: " + err)}
    };// 调用getUserHistory(),根据History数据库计算保底相关,写入last4star, last5star


    async diceCore(userID){
        let star = await this.getDiceStar(userID);
        let rand = Math.floor(Math.random()*(this.Pool[`All${star}Star`].length));// 随机抽取一位幸运角色
        let card = this.Pool[`All${star}Star`][rand];
        return {card, star};
    };
    async diceOnce(userID){
        if(this.primoGems[userID] < 160) return this.primoGems[userID];
        let {card, star} = await this.diceCore(userID)
        this.dbInsert("History", userID, {card, star, time: Date.now()});
        this.dbInsert("Inventory", userID, {card, star});
        this.primoGems[userID] -= 160;
        this.dbMember.update(userID, {$set: {primoGem: this.primoGems[userID]}});
        return {card, star, primoGem: this.primoGems[userID]};
    };
    async diceTenTimes(userID){
        if(this.primoGems[userID] < 1600) return this.primoGems[userID];
        let results = [];
        for(let i = 0; i < 10; i++){
            let {card, star} = await this.diceCore(userID);
            results.push({card, star});
            this.dbInsert("History", userID, {card, star, time: Date.now() + 0.1 * i});
            this.dbInsert("Inventory", userID, {card, star});
        };
        this.primoGems[userID] -= 1600;
        this.dbMember.update({userID: userID}, {$set: {primoGem: this.primoGems[userID]}});
        return {results, primoGem: this.primoGems[userID]};
    };
    async getDiceStar(userID){
        this.last5star[userID] += 1;
        this.last4star[userID] += 1;
        if     (this.last5star[userID] == 90){this.last5star[userID] = 0; return 5}// 吃满五星保底
        else if(this.last4star[userID] >= 10){this.last4star[userID] = 0; return 4}// 吃满四星保底(可能同时吃四五星保底导致last4star大于10)
        else{
            let rand = Math.floor(Math.random()*1000); // 0-999
            if     (rand <= 5 ){this.last5star[userID] = 0; return 5}// 0.6% 五星
            else if(rand <= 56){this.last4star[userID] = 0; return 4}// 5.1% 四星
            else return 3;
        };
    };// 根据当前用户的保底状态(laststar),吃保底直接返回保底对应星数,否则按概率随机抽取星数.最后更新保底状态


    async dbMemberFind(userID, type){
        return new Promise((resolve, reject) =>{
            this.dbMember.find({userID: userID}, (err, datas)=>{
                if (err) reject(err);
                else if (datas == []) resolve(null);
                else {
                    let res = new Array();
                    for (let data of datas) res.push(data[type]);
                    resolve(res);
                };
            })
        });
    };// 搜索dbMember中userID为userID的data, return [{data[types[0]]}, {data[types[1]]}...]
    async getUserHistory(userID){
        return new Promise((resolve, reject)=>{
            this.dbUserDatas["History"][userID].find({},(err, datas)=>{
                if(err) reject(err);
                else{
                    let history = new Array();
                    for(let i = 0; i < Math.min(90, datas.length); i++){
                        let dataMax = {time: 0, flag: -1};
                        for(let j in datas){
                            if(datas[j].time > dataMax.time)
                                {dataMax.time = datas[j].time; dataMax.flag = j};
                        };
                        history.push(datas[dataMax.flag]);
                        datas.splice(dataMax.flag, 1);
                    };
                    resolve(history);
                };
            });
        });
    };// 查找用户最近90条抽卡记录(不足90条就都取了), return [{timeMax,star,role}, ...{timeMin,star,role}]
    async getUserInventory(userID, type){
        let datas = await this.dbFind("Inventory", userID, type)
            .catch(err=>(console.log(`[ERROR]  dbFindInventoryERR: ${err}`)));
        return(await this.sortInventory(datas));
    };// 获得用户背包库存 return [{star,card,type,value}, ...]

    async sortInventory(datas){
        // 荷兰国旗 最对口的一集
        let left = 0;
        let right = datas.length - 1;
        
        for(let flag = left + 1; flag < right; flag++){
            if(datas[flag].star === 5){
                [datas[flag], datas[left]] = [datas[left], datas[flag]];
                left++;
            }
            else if(datas[flag].star === 3){
                [datas[flag], datas[right]] = [datas[right], datas[flag]];
                right--;
                flag--;
            };
        };
        return(datas);
    };
    
    async dbInsert(dbtype, userID, data){
        switch(dbtype){
            case "Inventory":
                this.dbUserDatas["Inventory"][userID].findOne(data, (err, doc)=>{
                    if(err) console.log(`[ERROR]  UserInventoryInsertERR: ${err}`);
                    else if(doc === null){
                        this.dbUserDatas["Inventory"][userID].insert(
                            {star: data.star, card: data.card, type: this.getCardType(data.star, data.card), value: 1},
                            (err)=>{if(err) console.log(`[ERROR]  ${dbtype}InsertERR: ${err}`)});
                    }else{
                        this.dbUserDatas["Inventory"][userID].update({card: data.card}, {$set: {value: (doc.value + 1)}},
                            (err)=>{if(err) console.log(`[ERROR]  ${dbtype}InsertERR: ${err}`)});
                    };
                });
                break;
            case "History":
                this.dbUserDatas["History"][userID].insert(data,
                    (err)=>{if(err) console.log(`[ERROR]  ${dbtype}InsertERR: ${err}`)});
            break;
        };
    };// 向userID的dbtype数据库插入data

    getCardType(star, card){
        let type = "unknown";
        if (star === 3) type = "weapon";
        else if (this.Pool[`${star}StarRole`].includes(card)) type = "role";
        else if (this.Pool[`${star}StarWeapon`].includes(card)) type = "weapon";
        return type;
    };

    async dbFind(dbtype, userID, type){
        return new Promise((resolve, reject) =>{
            let datatype = type ? {type: type} : {};
            this.dbUserDatas[dbtype][userID].find(datatype, (err, datas)=>{
                if(err) reject(err);
                else resolve(datas);
            });
        });
    };

    
    async signIn(userID){
        return new Promise((resolve, reject)=>{
            let content  = new String();
            let gemlist = [ 0, 20, 30, 50, 50, 
                           60, 60, 60, 60, 90, 90, 90, 120, 120, 120,
                           160, 160, 800, 1600, Infinity];
            this.dbMember.findOne({userID: userID},(err, datas)=>{
                console.log (userID);
                let date = new Date();
                if(datas.latestDate !== date.toLocaleDateString()){
                    let rand = Math.round(Math.random() * (gemlist.length - 1));
                    let primoGem = gemlist[rand];
                    if(rand === gemlist.length - 1)
                    content = `签到成功！\n恭喜你获得终极签到大奖: ${primoGem}原石!!!!! 这两天吃点好的,别睡太死<emoji:286>`;
                    else if ( rand === 0)
                    content = `签到成功！\n获得了${primoGem}原石......啊这...我不到啊<emoji:107>`;
                    else if ( rand >= 15)
                    content = `签到成功！\n获得了${primoGem}原石??! 我测? 什么情况?! 建议分我一半<emoji:108>`;
                    else if ( rand >= 5)
                    content = `签到成功！\n获得了${primoGem}原石! 继续加油捏`;
                    else 
                    content = `签到成功！\n获得了${primoGem}原石......额...你一定是没洗脸,明天再来吧<emoji:176>`;
                    primoGem += datas.primoGem;
                    this.dbMember.update({userID: userID}, 
                                         {$set: {primoGem: primoGem, latestDate: date.toLocaleDateString()}},
                                         (err, data)=>{if(data) resolve(content)});
                }
                else resolve(`今天已经签到过了哦,明天再来吧<emoji:355>`);
            
            });        
        });
    };
};


module.exports = Genshin;


    // async Init(userIDs){
    //     await this.memberInit(userIDs);
    // };// 先后调用memberInit, starInit进行初始化
    // async memberInit(userIDs){
    //     this.userIDs = userIDs;
    //     console.log("================UserDatasInit================");

    //     for (let userID of userIDs){
    //         for(let dbtype of ["Inventory", "History"]){
    //             fs.stat(`./res/DataBase/GenshinUser${dbtype}/User${userID}.db`,
    //             (err,stats) => {
    //                 if(err || stats.isFile()) {
    //                     this.dbUserDatas[dbtype][userID] 
    //                         = new nedb({filename: `./res/DataBase/GenshinUser${dbtype}/User${userID}.db`});
    //                     this.dbUserDatas[dbtype][userID].loadDatabase(()=>{
    //                         if(dbtype === "History") {};
    //                     });
    //                     console.log(`User${userID}.db \t${dbtype} 初始化`);
    //                 }else console.log(`User${userID}.db \t${dbtype}错误`);
    //             });
    //         };
    //         this.dbMemberFind(userID, "primoGem")
    //                 .then((primoGem)=> {
    //                     this.primoGems[userID] = primoGem ?? 0;
    //                     console.log(`User${userID}  \t${this.primoGems[userID]}原石`);
    //                 });
    //     };
    // };
    // async starInit(userID){
    //     try{
    //         let history = await this.getUserHistory(userID);
    //         for(let i = history.length - 1; i >= 0; i--){
    //             if(this.last5star[userID] !== undefined && this.last4star[userID] !== undefined)
    //                 break;
    //             else if(history[i].star === 5 && this.last5star[userID] === undefined)
    //                 this.last4star[userID] = history.length - 1 - i;
    //             else if(history[i].star === 4 && this.last4star[userID] === undefined)
    //                 this.last5star[userID] = history.length - 1 - i;
    //         };
    //         this.last5star[userID] = this.last5star[userID] ?? 0;
    //         this.last4star[userID] = this.last4star[userID] ?? 0;
    //         console.log("good");
    //     }catch(err){console.log("[ERROR]  GenshinUserStarInitERR: " + err)}
    // };// 调用getUserHistory(),根据History数据库计算保底相关,写入last4star, last5star